/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <flgrCoreIO.h>
#include <flgrCoreData.h>
#include <flgrCoreVector.h>
#include <flgrCoreSlideWindow.h>
#include <flgrCoreNhbManage.h>
#include <flgrCoreCopy.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreDataIO.h>
#include <flgrArith.h>
#include "flgrMorphoBase.h"
#include "flgrMorphoDistance.h"
#include "flgrMorphoDistanceFast.h"

/*!
 * \defgroup group_fulguro_core_morpho_dist Distance functions
 * \ingroup group_fulguro_morpho
 * \brief Morphological distance
 * @{
 */


////////////////////////////////////////////////////////////////////////////
// Macro flgr_get_distance
//////////////////////////////////////////////////////////////////
#define flgr_get_dist(dtype)					\
  int i,k;							\
  int spp = extr->spp;						\
  dtype *presult = (dtype *) result->array;			\
  dtype *center = (dtype*) extr->center_data_val->array;	\
  dtype *list_data_val;						\
  int *size = extr->size;					\
  dtype mini;							\
  dtype val;							\
  								\
  for(k=0 ; k<spp ; k++) {					\
    list_data_val = (dtype *) extr->list_data_val[k];		\
								\
    mini = flgr_get_array_##dtype(center,k);			\
    flgr_set_array_##dtype(presult,k,mini);			\
    if(mini==0) continue;					\
								\
    for(i=0 ; i<size[k] ; i++) {				\
      val = list_data_val[i];					\
      mini = (mini>val) ? val+1: mini;				\
    }								\
								\
    flgr_set_array_##dtype(presult,k,mini);			\
  }								\
								\
  return 



void flgr_get_distance_fgUINT8(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgUINT8);
}
void flgr_get_distance_fgUINT16(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgUINT16);
}
void flgr_get_distance_fgUINT32(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgUINT32);
}
void flgr_get_distance_fgINT8(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgINT8);
}
void flgr_get_distance_fgINT16(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgINT16);
}
void flgr_get_distance_fgINT32(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgINT32);
}
void flgr_get_distance_fgFLOAT32(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgFLOAT32);
}
void flgr_get_distance_fgFLOAT64(FLGR_Vector *result, FLGR_NhbBox2D *extr) {
  flgr_get_dist(fgFLOAT64);
}


////////////////////////////////////////////////////////////////////////////
// Macro function for different type of flgr2d_distance_dtype
//////////////////////////////////////////////////////////////////
#define flgr_dist(dtype,dtypename)					\
  FLGR_Data2D *nhb;							\
  FLGR_Type type = imgsrc->type;					\
  FLGR_Type spp = imgsrc->spp;						\
	 								\
  FLGR_DECLARE_FUNCTION;						\
									\
  nhb = flgr2d_create_neighborhood_from_connexity(spp,type, connexity);	\
									\
  flgr2d_copy(imgdest,imgsrc);						\
									\
  switch(connexity) {							\
  case FLGR_4_CONNEX:							\
    flgr2d_distance_raster_4_connexity_##dtype(imgdest);		\
    break;								\
  case FLGR_6_CONNEX:							\
    flgr2d_distance_raster_6_connexity_##dtype(imgdest);		\
    break;								\
  case FLGR_8_CONNEX:							\
    flgr2d_distance_raster_8_connexity_##dtype(imgdest);		\
    break;								\
  default:								\
    flgr2d_raster_slide_window_##dtype(imgdest,imgdest,nhb,		\
				       FLGR_NHB_NO_SYM,			\
				       flgr_get_distance_##dtype);	\
  }									\
  									\
  switch(connexity) {							\
  case FLGR_4_CONNEX:							\
    flgr2d_distance_antiraster_4_connexity_##dtype(imgdest);		\
    break;								\
  case FLGR_6_CONNEX:							\
    flgr2d_distance_antiraster_6_connexity_##dtype(imgdest);		\
    break;								\
  case FLGR_8_CONNEX:							\
    flgr2d_distance_antiraster_8_connexity_##dtype(imgdest);		\
    break;								\
  default:								\
    flgr2d_anti_raster_slide_window_##dtype(imgdest,imgdest,nhb,	\
					    FLGR_NHB_NO_SYM,		\
					    flgr_get_distance_##dtype);	\
  }									\
									\
  flgr2d_destroy(nhb);							\
									\
  return FLGR_RET_OK

FLGR_Ret flgr2d_distance_fgBIT(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_no_define_type_function(FLGR_BIT);
  return FLGR_RET_NOT_IMPLEMENTED;
}
FLGR_Ret flgr2d_distance_fgUINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgUINT8,FLGR_UINT8);
}
FLGR_Ret flgr2d_distance_fgUINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgUINT16,FLGR_UINT16);
}
FLGR_Ret flgr2d_distance_fgUINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgUINT32,FLGR_UINT32);
}
FLGR_Ret flgr2d_distance_fgINT8(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_no_define_type_function(FLGR_INT8);
  return FLGR_RET_NOT_IMPLEMENTED;
}
FLGR_Ret flgr2d_distance_fgINT16(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgINT16,FLGR_INT16);
}
FLGR_Ret flgr2d_distance_fgINT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgINT32,FLGR_INT32);
}
FLGR_Ret flgr2d_distance_fgFLOAT32(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgFLOAT32,FLGR_FLOAT32);
}
FLGR_Ret flgr2d_distance_fgFLOAT64(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  flgr_dist(fgFLOAT64,FLGR_FLOAT64);
}


////////////////////////////////////////////////////////////////////////////
/*! Compute Distance function on binary image (0,255)
 *  @param imgdest : image output
 *  @param imgsrc : image input
 *  @param connexity : connexity to use
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_distance(FLGR_Data2D *imgdest, FLGR_Data2D *imgsrc, FLGR_Connexity connexity) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((imgdest==NULL) || (imgsrc==NULL)){
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((connexity != FLGR_4_CONNEX) && (connexity != FLGR_6_CONNEX) && (connexity != FLGR_8_CONNEX)) {
    POST_ERROR("unknown connexity\n");
    return FLGR_RET_CONNEXITY_UNKNOWN;
  }

  if((ret=flgr2d_is_data_same_attributes(imgdest,imgsrc,__FUNCTION__))!=FLGR_RET_OK) return ret;

  FLGR_DISPATCH_FUNCTION(FLGR_RET_TYPE_UNKNOWN,imgdest->type,flgr2d_distance,imgdest,imgsrc,connexity);

}


//! @}
